package pay

import (
	"context"
	"fmt"
	"gitee.com/bobo-rs/innovideo-services/enums"
	"gitee.com/bobo-rs/innovideo-services/framework/model"
	"gitee.com/bobo-rs/innovideo-services/library/services/pay"
	"net/url"
	"strings"
	"time"
)

const (
	tradeNoSeq = `-`
)

// Payment 去支付
func (p *sPay) Payment(ctx context.Context, in model.PaymentInput) (interface{}, error) {
	config, err := p.Config(ctx)
	if err != nil {
		return nil, err
	}

	// 获取前置支付信息
	res, err := p.beforePaymentEvent(ctx, in.PaymentItem)
	if err != nil {
		return nil, err
	}

	// 其他参数
	other := p.processPaymentOther(res, config, in)

	// 去支付
	resp, err := pay.New().Register(ctx, string(in.PayType)).Payment(ctx, p.GenTradeNo(in.No), res.Amount, other)
	if err != nil {
		return nil, err
	}

	// 后置支付事件
	err = p.afterPaymentEvent(ctx, in.PaymentItem, resp)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

// ConfirmPayment 确认支付（PayPal必须）
func (p *sPay) ConfirmPayment(ctx context.Context, payNo string, payType enums.PayType, f func(ctx context.Context, tradeNo string) (interface{}, error)) (interface{}, error) {
	// 调用支付确认
	res, err := pay.New().Register(ctx, string(payType)).ConfirmPayment(ctx, payNo)
	if err != nil {
		return nil, err
	}
	return f(ctx, res.TradeNo)
}

// GenTradeNo 通过订单号生成商户交易号
func (p *sPay) GenTradeNo(no string) string {
	return fmt.Sprintf(`%s-%d`, no, time.Now().Unix())
}

// SplitTradeNo 从商户交易单号中拆出订单号
func (p sPay) SplitTradeNo(tradeNo string) string {
	if tradeNo == `` {
		return ""
	}
	return strings.Split(tradeNo, tradeNoSeq)[0]
}

// processPaymentOther 处理其他参数
func (p *sPay) processPaymentOther(res *model.PaymentResultData, config *model.PayConfig, in model.PaymentInput) map[string]interface{} {
	var (
		returnUrl = config.ReturnUrl
		cancelUrl = config.CancelUrl
	)

	// 各业务场景回调跳转地址
	if rUrl, ok := res.Other[`return_url`]; ok {
		returnUrl = rUrl.(string)
	}
	if cUrl, ok := res.Other[`cancel_url`]; ok {
		cancelUrl = cUrl.(string)
	}

	// 构造URL请求参数
	urlValues := url.Values{}
	urlValues.Add(`pay_type`, string(in.PayType))
	urlValues.Add(`order_no`, in.No)

	// 其他参数
	other := map[string]interface{}{
		`return_url`: fmt.Sprintf(`%s?%s`, returnUrl, urlValues.Encode()),
		`cancel_url`: fmt.Sprintf(`%s?%s`, cancelUrl, urlValues.Encode()),
		`content`:    res.Content,
		`currency`:   config.Currency,
	}
	return other
}
